package cn.yueranzs.login.service.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import cn.yueranzs.config.JwtConfig;
import cn.yueranzs.handler.BusinessException;
import cn.yueranzs.response.RedisResultCode;
import cn.yueranzs.system.pojo.User;
import cn.yueranzs.utils.JwtUtil;
import cn.yueranzs.utils.RedisUtil;
import lombok.extern.slf4j.Slf4j;
import org.springframework.security.authentication.UsernamePasswordAuthenticationToken;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.web.authentication.WebAuthenticationDetailsSource;
import org.springframework.stereotype.Component;
import org.springframework.web.filter.OncePerRequestFilter;

import javax.annotation.Resource;
import javax.servlet.FilterChain;
import javax.servlet.ServletException;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * jwttokenfilter
 * @author yueranzs
 * @date 2021/12/4 10:14
 */
@Slf4j
@Component
public class JwtAuthenticationTokenFilter extends OncePerRequestFilter {

    @Resource
    private UserDetailsService userDetailsService;

    @Resource
    private JwtUtil jwtUtil;

    @Resource
    private JwtConfig jwtConfig;

    @Override
    protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {
        String requestUrl = request.getRequestURI();
        String authToken = request.getHeader(jwtConfig.getHeader());
        String userName = null;
        if (ObjectUtil.isNotEmpty(authToken)) {
            userName = jwtUtil.getUserNameToken(authToken);
        }

        log.info("进入jwt自定义token过滤器");
        log.info("自定义token过滤器获得用户名为：" + userName);

        //当userName不为空时进行校验token是否为有效token
        if (ObjectUtil.isNotEmpty(userName) && ObjectUtil.isNull(SecurityContextHolder.getContext().getAuthentication())) {
            UserDetails userDetails = this.userDetailsService.loadUserByUsername(userName);
            User user = (User) userDetails;
            //检验token
            if(ObjectUtil.isEmpty(RedisUtil.get(RedisResultCode.REDIS_TOKEN_CODE.getMessage() + userName))){
                throw new BusinessException(500,"token已被清除");
            } else if (!jwtUtil.verifyToken(authToken)) {
                throw new BusinessException(500,"token已过期");
            }else if (StrUtil.equals(userName,user.getUsername())) {
                /**
                 * UsernamePasswordAuthenticationToken继承AbstractAuthenticationToken实现Authentication
                 * 所以当在页面中输入用户名和密码之后首先会进入到UsernamePasswordAuthenticationToken验证(Authentication)，
                 * 然后生成的Authentication会被交由AuthenticationManager来进行管理
                 * 而AuthenticationManager管理一系列的AuthenticationProvider，
                 * 而每一个Provider都会通UserDetailsService和UserDetail来返回一个
                 * 以UsernamePasswordAuthenticationToken实现的带用户名和密码以及权限的Authentication
                 */
                //清除密码
                user.setPassword(null);
                UsernamePasswordAuthenticationToken authentication = new UsernamePasswordAuthenticationToken(userDetails, null, userDetails.getAuthorities());
                authentication.setDetails(new WebAuthenticationDetailsSource().buildDetails(request));
                //将authentication放入SecurityContextHolder中
                SecurityContextHolder.getContext().setAuthentication(authentication);
            }
        }
        filterChain.doFilter(request,response);
    }
}
